import type { AxiosInstance, AxiosRequestConfig, Canceler } from 'axios'
import axios, { type AxiosProgressEvent } from 'axios'

import type { ApiRequest, HttpResponse } from '@/types/apis'

const CancelToken = axios.CancelToken
class HttpRequest {
  private baseUrl: string
  private pending: Record<string, Canceler>

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl
    this.pending = {}
  }
  /** 获取配置 */
  private getConfig() {
    return {
      baseURL: this.baseUrl,
      headers: {
        'Content-Type': 'application/json;charset=utf-8'
      },
      timeout: 60000
    }
  }

  private interceptors(instance: AxiosInstance) {
    // 请求拦截
    instance.interceptors.request.use(async (config: any) => {
      // config!.headers![projectSettings.deviceId] = appStore.murmur
      const key = config.url + '&' + config.method
      // this.removePending(key, true)
      config.cancelToken = new CancelToken(
        (cancel: any) => (this.pending[key] = cancel)
      )
      return config
    })
    // 响应拦截

    instance.interceptors.response.use(
      async res => {
        if (res.data.code === 6200) {
          return Promise.resolve(res.data)
        }
        // const key = res.config.url + '&' + res.config.method
        // this.removePending(key)
        // if (res.data.code === 6200) {
        //   return Promise.resolve(res.data)
        // } else {
        // ElNotification.closeAll()
        if (res.data.code === 6401) {
          // ElNotification.error({
          //   title: '失败',
          //   customClass: 'notification-error',
          //   message: res.data.msg
          // })
          throw new Error('未经授权')
        }
        // ElNotification.error({
        //   title: '失败',
        //   customClass: 'notification-error',
        //   message: res.data.msg
        // })
        return Promise.reject(res.data)
        // return Promise.    // if (res.data.code === 6200) {
        //   return Promise.resolve(res.data)
        // }(res as any)
      },
      err => {
        if (
          err.code === 'ECONNABORTED' ||
          err.message === 'Network Error' ||
          err.message.includes('timeout')
        ) {
          // ElMessage({
          //   message: '请求超时，请稍后重试',
          //   grouping: true,
          //   type: 'error'
          // })
        }

        // const code = err.response?.data?.code || 0
        // if (code) {
        //   ElMessage.error(err.response.data.message || err.message)
        // } else {
        //   ElMessage.error(ERROR_CODE[err.response?.status])
        // }

        return Promise.reject(err)
      }
    )
  }

  http<D = any>(options: AxiosRequestConfig) {
    const config = Object.assign(this.getConfig(), options)
    const instance = axios.create(config)
    this.interceptors(instance)
    return instance.request<HttpResponse<D>>(config)
  }

  get<T extends keyof ApiRequest, D>(
    url: string,
    params?: ApiRequest[T],
    config?: AxiosRequestConfig
  ): Promise<HttpResponse<D>> {
    const options = Object.assign({ url, params }, config)
    return new Promise((resolve, reject) => {
      this.http(options)
        .then(res => {
          return resolve(res as unknown as HttpResponse<D>)
        })
        .catch(err => {
          return reject(err)
        })
    })
  }
  put<T extends keyof ApiRequest, D>(
    url: string,
    data?: ApiRequest[T],
    config?: AxiosRequestConfig
  ): Promise<HttpResponse<D>> {
    const options = Object.assign({ url, data, method: 'PUT' }, config)
    return new Promise((resolve, reject) => {
      this.http(options)
        .then(res => {
          return resolve(res as unknown as HttpResponse<D>)
        })
        .catch(err => {
          return reject(err)
        })
    })
  }
  post<T extends keyof ApiRequest, D>(
    url: string,
    data?: ApiRequest[T],
    config?: AxiosRequestConfig
  ): Promise<HttpResponse<D>> {
    const options = Object.assign({ url, data, method: 'POST' }, config)
    return new Promise((resolve, reject) => {
      this.http(options)
        .then(res => {
          return resolve(res as unknown as HttpResponse<D>)
        })
        .catch(err => {
          return reject(err)
        })
    })
  }
  upload<T>(
    url: string,
    data: any,
    onUploadProgress: (e: AxiosProgressEvent) => void
  ): Promise<any> {
    const options = Object.assign(
      { url, data, method: 'POST' },
      { headers: { 'Content-Type': 'multipart/form-data' } }
    )
    return new Promise((resolve, reject) => {
      this.http({ ...options, onUploadProgress })
        .then(res => {
          return resolve(res as unknown as T)
        })
        .catch(err => {
          return reject(err)
        })
    })
  }
}
export default HttpRequest
